#include "channel.h"
#include "sysconfig.h"
#include "dp_common.h"
#include <fstream>
#include <nlohmann/json.hpp>
#include "server.h"
#include "spdlog/spdlog.h"



using json = nlohmann::json;

void scan_group::add_dp(shared_DChanneldpPtr dp)
{
    if(cnt ==0)
    {
        func = dp->m_funcCode;
        startReg = dp->m_regStart;
        cnt+=dp->m_regCount;
        endReg = dp->m_regStart;
        slaveID = dp->m_slaveId;
    }
    else{
        cnt+=dp->m_regCount;
        endReg = dp->m_regStart;
    }
    m_group.push_back(dp);
    printf("====add dp into scan group:slave(%d),func(%d),reg(%d)\n", slaveID, func, dp->m_regStart);
}
bool scan_group::is_suitable(shared_DChanneldpPtr dp)
{
    //正好是下一个，则合适本组，返回ture， 否则false
    return (dp->m_funcCode == func) && ((endReg+1)==dp->m_regStart) ;
}


Channel_modbus_rtu::Channel_modbus_rtu(shared_DChannelPtr dp)
{
    m_channel_cfg = dp;
    //m_channel_cfg= dp;
    //解析json
    /*
        {"com":"ttyS3","baudrate":9600,"datawidth":8,"stop":1,"oddeven":0,"logInterval":500}
        {"ip":"192.168.31.100","port":53435,"logInterval":500}
    */
    json data = json::parse(m_channel_cfg->param);
    if(data.size()!=0)
    {
        uart_com = data["com"];
        baudrate = data["baudrate"];
        stop = data["stop"];
        oddeven = data["oddeven"];
        logInterval = data["logInterval"];
    }
    //连接ctx
    m_slaveid = dp->chid;
    string  ip_or_device="/dev/"+uart_com;
    printf("rtu channel: uart_com=%s, baudrate=%d, stop=%d, odeven=%d\n",ip_or_device.c_str(),baudrate,stop,oddeven);
    m_ctx = modbus_new_rtu(ip_or_device.c_str(), baudrate, 'N', 8, 1);
    if(m_ctx != NULL)
    {
        m_workState = ECH_MB_RTU_WORK_STATE_NORMAL;
    }
    else{
        printf("rtu channel create failed\n");
    }
    modbus_set_slave(m_ctx,m_slaveid);
}
;
void  Channel_modbus_rtu::init(vector<shared_DChanneldpPtr>& dps)
{
    int subgrpId = -1;
    int addr = -1;
    int func = -1;
    int regStartAddr = 0;
    int regEndAddr = 0;
    int regCnts = 0;
    bool bNewGrp = false;
    vector<shared_DChanneldpPtr> onegroup_dps;
    shared_scanGroupPtr onegroup;
    //读取dps, 进行分类
    sort_dps(dps);
    //构造组
    for(auto dp:m_channel_dps)
    {
        func = dp->m_funcCode;
        if(dp->m_bScan)
        {
            if(m_dps_groups.find(func) == m_dps_groups.end())
            {
                //不存在组
                onegroup.reset(new scan_group());
                printf("func(%d),group index 0\n", func);
                onegroup->add_dp(dp);
                m_dps_groups[func] = {onegroup};
            }
            else{
                auto& grps = m_dps_groups[func];
                int is_add = 0;
                for(auto& grp:grps)
                {
                    if(grp->is_suitable(dp))
                    {
                        grp->add_dp(dp);
                        is_add = 1;
                        break;
                    }
                }
                if(!is_add)
                {
                    //不存在合适组，创建新组
                    onegroup.reset(new scan_group());
                    printf("func(%d),group index %d\n", func,m_dps_groups[func].size());
                    onegroup->add_dp(dp);
                    m_dps_groups[func].push_back(onegroup);
                }
            }
        }
    }
}
void Channel_modbus_rtu::sort_dps(vector<shared_DChanneldpPtr>& dps)
{
    for(auto dp:dps)
    {
        //属于本channel的dp点位
        if(dp->chid == m_channel_cfg->chid)
        {
            printf("dp->tag:%s,dp->enable:%d\n",dp->tag.c_str(),dp->enable);
            if(0 == dp->enable)
            {
                continue;
            }
            int groupid = dp->m_jsonparam.groupId;
            int slaveid = dp->m_jsonparam.slaveId;
            int fc_code = dp->m_jsonparam.fc_code;

            dp->m_jsonparam.groupId = slaveid*10000+fc_code*100+groupid;
            dp->m_bScan = true;
            m_channel_dps.push_back(dp);
        }
    }
    sort(m_channel_dps.begin(),m_channel_dps.end(),[](const shared_DChanneldpPtr& a,const shared_DChanneldpPtr& b){
        if(a->m_jsonparam.slaveId != b->m_jsonparam.slaveId)
        {
            return a->m_jsonparam.slaveId < b->m_jsonparam.slaveId;
        }else{
            if(a->m_jsonparam.fc_code != b->m_jsonparam.fc_code)
            {
                return a->m_jsonparam.fc_code < b->m_jsonparam.fc_code;
            }else{
                 return a->m_jsonparam.regStart < b->m_jsonparam.regStart;
            }
        }
    });
}

void Channel_modbus_rtu::handle_scan_dps()
{
    //slaveid->fcode->[index,scangroups]
    //
    uint8_t oldAddr = 0xff;
    uint64_t startMs = 0;//CMisc::get_runms();
    uint64_t endMs = 0;
    int nb_fail = 1;
    if(m_dps_groups.size() == 0)
    {
        //没有组，不需要扫描
        return;
    }
    //auto pgrp = m_dps_groups[m_curScanGrpI++%m_grps.size()];
    while(1){
    for(auto &pgrp:m_dps_groups)
    {
        for(auto scangroup : pgrp.second)
        {
            int addr = scangroup->startReg;
            int nb = scangroup->cnt;
            int fc = scangroup->func;
            uint8_t tab_rp_bits[128];
            uint8_t tab_rp_inputbits[128];
            uint16_t tab_rp_registers[128];
            uint16_t tab_rp_inputregisters[128];
            //if(nb_fail > 3)
            //{
            //    printf("modbus rtu scan dps group:%d,slaveid:%d,func:%d,regCount:%d, try cnt:%d, exceed max try cnt\n",pgrp.first,addr,fc,nb,nb_fail);
               // continue;
            //}
            int rc = 0;
            switch(fc)
            {

                case MODBUS_FC_READ_COILS:
                    {
                        rc = modbus_read_bits(m_ctx, addr, nb, tab_rp_bits);
                        if (rc == -1 ) {
                            printf("ERROR modbus_read_bits single (%d)\n", rc);
                            printf("address = %d\n", addr);
                            nb_fail++;
                            }
                        else{
                            //处理数据
                            handle_group_response(scangroup,tab_rp_bits);

                        }
                        //更新 数据库和slave
                    }
                    break;
                case MODBUS_FC_READ_DISCRETE_INPUTS:
                        rc = modbus_read_input_bits(m_ctx, addr, nb, tab_rp_inputbits);
                        if (rc == -1 ) {
                            printf("ERROR modbus_read_input_bits single (%d)\n", rc);
                            printf("address = %d\n", addr);
                            nb_fail++;
                            }
                        else{
                            //处理数据
                            handle_group_response(scangroup,tab_rp_bits);
                        }
                    break;
                case MODBUS_FC_READ_HOLDING_REGISTERS:
                    rc = modbus_read_registers(m_ctx, addr, nb, tab_rp_registers);
                        if (rc == -1 ) {
                            printf("ERROR modbus_read_registers single (%d)\n", rc);
                            printf("address = %d\n", addr);
                            nb_fail++;
                            }                        
                            else{
                            //处理数据
                            handle_group_response(scangroup,tab_rp_bits);
                        }
                    break;
                case MODBUS_FC_READ_INPUT_REGISTERS:
                    rc = modbus_read_input_registers(m_ctx, addr, nb, tab_rp_inputregisters);
                        if (rc == -1 ) {
                            printf("ERROR modbus_read_input_registers single (%d)\n", rc);
                            printf("address = %d\n", addr);
                            nb_fail++;
                            }
                        else{
                            //处理数据
                            handle_group_response(scangroup,tab_rp_bits);
                        }
                    break;
                default:
                    rc = 0;
                    break;
            }
             std::this_thread::sleep_for(std::chrono::milliseconds(1));

        }
    }
    }
}
void Channel_modbus_rtu::handle_group_response(shared_scanGroupPtr grp,uint8_t *resp)
{
    //更新数据库
    //更新slave
    int data;
    int startreg = grp->startReg;
    if(grp->func == MODBUS_FC_READ_COILS || grp->func == MODBUS_FC_READ_DISCRETE_INPUTS)
    {
        int index = 0;
        for(auto dp:grp->m_group)
        {
            msg_update_ptr msg(new msg_update_value);
            memcpy(&msg->m_dpparam,&dp->m_jsonparam,sizeof(msg->m_dpparam));
            msg->m_dpparam.regValue = (uint8_t)resp[index];
            index++;
            mbserver_mgr::getInstance()->put_msg(msg);
        }
    }
    else if(grp->func == MODBUS_FC_READ_HOLDING_REGISTERS || grp->func == MODBUS_FC_READ_INPUT_REGISTERS)
    {
        uint16_t *nresp = (uint16_t*)resp;
        int index = 0;
        for(auto dp:grp->m_group)
        {
            msg_update_ptr msg(new msg_update_value);
            memcpy(&msg->m_dpparam,&dp->m_jsonparam,sizeof(msg->m_dpparam));
            msg->m_dpparam.regValue = (uint16_t)nresp[index];
            index++;
            mbserver_mgr::getInstance()->put_msg(msg);
        }
    }

}


//----------------------------------------------------------------
Channel_modbus_tcp::Channel_modbus_tcp(shared_DChannelPtr dp)
{

}
void  Channel_modbus_tcp::init(vector<shared_DChanneldpPtr>&)
{

}
void  Channel_modbus_tcp::deinit()
{

}
void Channel_modbus_tcp::sort_dps()
{

}
void Channel_modbus_tcp::handle_scan_dps()
{

}
void Channel_modbus_tcp::process(const std::string& data)
{

}


//ChannelMgr

void Channelmgr::init()
{
    shared_ChannelPtr pChannel =nullptr;
    vector<shared_DChannelPtr> chs;
    sysconfig::m_confdb->get_channel_dps(m_dpsTemp);
    sysconfig::m_confdb->get_channels(chs);
    for(auto pdp:m_dpsTemp)
    {
        pdp->initjsonparam();
    }
    for(auto ch:chs){
        printf("Channel:chid:%d,enable:%d,param:%s\n", ch->chid,ch->enable,ch->param.c_str());
    if(ch->enable){
        switch (ch->drvtype){
        case ECH_TYPE_MODBUS_RTU:{
            pChannel.reset(new Channel_modbus_rtu(ch));
            pChannel->init(m_dpsTemp);
            m_channels[pChannel->get_channelid()] = pChannel;
            //CModule_Mgr::getInstance()->reg_module(pChannel->m_moduleId,pChannel);

        }   
            break;
        case ECH_TYPE_MODBUS_TCP:{
            pChannel.reset(new Channel_modbus_tcp(ch));
            pChannel->init(m_dpsTemp);
            m_channels[pChannel->get_channelid()] = pChannel;
            //CModule_Mgr::getInstance()->reg_module(pChannel->m_moduleId,pChannel);
        }
            break;
        default:
            break;
        }
    }
    }
    spdlog::info("channel mgr init end\n");
}

void Channelmgr::start(){
    for(auto pCh : m_channels){
        pCh.second->process("");
        //CMsg_Ptr pMsg(new CMsg_Start());
        //pCh.second->put_msg(pMsg);
    }
}

vector<dp_param_t> Channelmgr::get_param()
{
    vector<dp_param_t> vec;
    for(auto pCh : m_dpsTemp)
    {
        vec.push_back(pCh->m_jsonparam);
    }
    return vec;
}